package com.umpay.business.consume.impl;

import com.umpay.business.common.MgrCommonBusiness;
import com.umpay.business.consume.ConsumeH5NotifyBusiness;
import com.umpay.controller.base.AbstractController;
import com.umpay.dict.DataDict;
import com.umpay.dict.XmlData;
import com.umpay.dict.XmlData4Mer;
import com.umpay.dict.retcode.MerAccessEC;
import com.umpay.dict.retcode.MerBusiEC;
import com.umpay.dto.UMFResponse.Message;
import com.umpay.dto.UMFResponse.Message.Meta;
import com.umpay.dto.memberMgr.res.MerInfRes;
import com.umpay.dto.merBusi.req.consume.ConsumeH5NotifyBusiReq;
import com.umpay.dto.merBusi.res.consume.ConsumeH5NotifyBusiRes;
import com.umpay.exception.BusinessException;
import com.umpay.feign.client.ConsumeBusiServerFeignClient;
import com.umpay.util.HashSignHelper;
import com.umpay.util.PropertyUtil;
import com.umpay.util.StringUtils;
import com.umpay.util.TimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: ConsumeH5NotifyBusinessImpl  
 * @Description: H5交易前后台通知处理  
 * @author zhangtao  
 * @date Mar 15, 2018
 */
@Component
public class ConsumeH5NotifyBusinessImpl extends AbstractController implements ConsumeH5NotifyBusiness {
    
	private static final Logger log = LoggerFactory.getLogger(ConsumeH5NotifyBusinessImpl.class);
    
	@Autowired
	private PropertyUtil propertyUtil;
	
	@Autowired
	private ConsumeBusiServerFeignClient consumeBusiServerFeignClient;
	@Autowired
	private MgrCommonBusiness mgrCommonBusinessImpl;
	
	@Override
	public ModelAndView consumeH5FrontNotify(Map<String, Object> reqMap) {
		log.info("【H5支付paygate前台通知--步骤1】请求参数校验");
		checkRequestParameter(reqMap);
		log.info("【H5支付paygate前台通知--步骤2】请求业务线确认结果");
		Message<ConsumeH5NotifyBusiRes> merBusiRes = requestBusiPayConfirm(reqMap,DataDict.NOTIFY_TYPE_FRONT);
		log.info("【H5支付paygate前台通知--步骤3】通知商户支付结果");
		return redirectMerPage(merBusiRes);
	}
    
	@Override
	public void consumeH5BackNotify(Map<String, Object> reqMap,HttpServletResponse response) {
		log.info("【H5支付paygate后台通知--步骤1】请求参数校验");
		checkRequestParameter(reqMap);
		log.info("【H5支付paygate后台通知--步骤2】请求业务线确认结果");
		Message<ConsumeH5NotifyBusiRes> merBusiRes = requestBusiPayConfirm(reqMap,DataDict.NOTIFY_TYPE_BACKGROUND);
		log.info("【H5支付paygate后台通知--步骤3】响应paygate");
		assembleResponseData(merBusiRes,response);
	}
	
	private ModelAndView redirectMerPage(Message<ConsumeH5NotifyBusiRes> merBusiRes) {
		try {
			String retCode = null;
			String retMsg = null;
			if(merBusiRes !=null) {
				String notifyPayState = merBusiRes.getData().getNotifyPayState();
				retCode = merBusiRes.getMeta().getRet_code();
				if(StringUtils.isEmpty(notifyPayState)) {
					retCode = MerAccessEC.RESULT_UNKNOWN;//支付不明 
					retMsg = "支付不明";
				}else if(notifyPayState.equals(DataDict.PAYSTATE_SUCCESS) && retCode.equals(MerAccessEC.SUCCESS)){
					retCode = MerAccessEC.SUCCESS;//支付成功
					retMsg = "支付成功";
				}else if(notifyPayState.equals(DataDict.PAYSTATE_H5PAY_FAILED)) {
					retCode = MerBusiEC.CONSUME_FAIL;//支付失败
					retMsg = "支付失败";
				}else {
					retCode = MerAccessEC.RESULT_UNKNOWN;//支付不明 
					retMsg = "支付不明";
				}
			}
			else {
				retCode = MerAccessEC.RESULT_UNKNOWN;//支付不明 
				retMsg = "支付不明";
			}
			String retUrl = StringUtils.trim(merBusiRes.getData().getRetUrl());
			Message<Map<String,String>> notifyMessage = new Message<Map<String,String>>();
			notifyMessage.setMeta(new Meta(retCode,retMsg));
			Map<String,String> notifyMap = new HashMap<String,String>();
			ConsumeH5NotifyBusiRes resInfo = merBusiRes.getData();
			if(resInfo != null) {
				notifyMap.put(XmlData4Mer.MER_ID, resInfo.getMerId());
				notifyMap.put(XmlData4Mer.SETTLE_AMT, resInfo.getSettleAmt());
				notifyMap.put(XmlData4Mer.VERSION,resInfo.getVersion());
				notifyMap.put(XmlData4Mer.BUSI_TYPE,resInfo.getBusiType());
				notifyMap.put(XmlData4Mer.ORDER_ID,resInfo.getOrderId());
				notifyMap.put(XmlData4Mer.MER_DATE,resInfo.getOrderDate());
				notifyMap.put(XmlData4Mer.TRADE_NO,resInfo.getTradeNo());
				notifyMap.put(XmlData4Mer.MER_TRACE,resInfo.getMerTrace());
				notifyMap.put(XmlData.AMOUNT,resInfo.getAmount());
				notifyMap.put(XmlData4Mer.TRADE_NO,resInfo.getTradeNo());
				notifyMap.put(XmlData4Mer.MER_CHECK_DATE,resInfo.getMerCheckDate());
			}
			notifyMessage.setData(notifyMap);
			String  redirectUrl = "redirect:" + retUrl + "?" + getAssembleFrontUrl(notifyMessage);
			log.info(String.format("通知商户支付结果[%s]", redirectUrl));
            return new ModelAndView(redirectUrl);
			
           
		}catch(BusinessException e){
            log.error(String.format("【H5消费前台通知】消费通知异常：[%s：%s]",e.getCode(), e.getMessage()));
            throw new BusinessException(e.getCode(), e.getMessage());
		}catch(Exception e){
            log.error(String.format("【H5消费前台通知】消费通知异常：[%s：%s]",MerAccessEC.SYSTEM_ERR, e.getMessage()));
            throw new BusinessException(MerAccessEC.SYSTEM_ERR, "系统忙，请稍后再试");
        }
	}
	private void assembleResponseData(Message<ConsumeH5NotifyBusiRes> merBusiRes,HttpServletResponse response) {
		if(merBusiRes != null) {
			String notifyPayState = merBusiRes.getData().getNotifyPayState();
			//是终态直接响应，不需要继续通知
			if(notifyPayState.equals(DataDict.PAYSTATE_SUCCESS) || notifyPayState.equals(DataDict.PAYSTATE_H5PAY_FAILED)) {
				String retCode = MerAccessEC.SUCCESS;
				String retMsg = "确认完成";
				merBusiRes.setMeta(new Meta(retCode,retMsg));
				PrintWriter pw;
				try {
					pw = response.getWriter();
					log.info(String.format("H5支付确认后台通知返回给支付网关数据为：%s",merBusiRes));
					pw.write(merBusiRes.toString());
					pw.close();
				} catch (IOException e) {
					log.info(MerAccessEC.SYSTEM_ERR,"【退费确认后台通知】响应支付网关异常！");
					e.printStackTrace();
				}
			}
		}else {
			throw new BusinessException(MerAccessEC.SYSTEM_ERR, "系统异常");
		}
	}
	private Message<ConsumeH5NotifyBusiRes> requestBusiPayConfirm(Map<String, Object> reqMap,String notifyType) {
		ConsumeH5NotifyBusiReq h5BusiReq= new ConsumeH5NotifyBusiReq();
		String bProductId = StringUtils.trim(propertyUtil.getProperty("bsp.bproductid"));  //基础业务产品
		h5BusiReq.setVersion(DataDict.VERSION);
		h5BusiReq.setbProductId(bProductId);
		h5BusiReq.setAmount(StringUtils.trim(reqMap.get(XmlData.AMOUNT)));
		h5BusiReq.setInstId(StringUtils.trim(reqMap.get(XmlData.INSTID)));
		h5BusiReq.setMerId(StringUtils.trim(reqMap.get(XmlData.MERID)));
		if(DataDict.NOTIFY_TYPE_FRONT.equals(notifyType)) {
			h5BusiReq.setRpid("FRONT_" + StringUtils.trim(reqMap.get(XmlData.TRACE)));
		}else {
			h5BusiReq.setRpid("BACK_" + StringUtils.trim(reqMap.get(XmlData.TRACE)));
		}
		h5BusiReq.setTrace(StringUtils.trim(reqMap.get(XmlData.TRACE)));
		h5BusiReq.setOrderId(StringUtils.trim(reqMap.get(XmlData.ORDERID)));
		h5BusiReq.setOrderDate(StringUtils.trim(reqMap.get(XmlData.ORDERDATE)));
		h5BusiReq.setPayState(StringUtils.trim(reqMap.get(XmlData.PAYSTATE)));
		h5BusiReq.setStlDate(StringUtils.trim(reqMap.get(XmlData.STLDATE)));
		h5BusiReq.setRetCode(StringUtils.trim(reqMap.get(XmlData.RETCODE)));
		h5BusiReq.setRetMsg(StringUtils.trim(reqMap.get(XmlData.RETMSG)));
		h5BusiReq.setPaySeq(StringUtils.trim(reqMap.get(XmlData.PAYSEQ)));
		h5BusiReq.setReqDate(TimeUtil.date8());
		h5BusiReq.setReqTime(TimeUtil.time6());
		h5BusiReq.setPayType(StringUtils.trim(reqMap.get(XmlData.PAYTYPE)));
		//统一传入接入类型
		MerInfRes merInfRes = getMerInfo(h5BusiReq.getMerId(),h5BusiReq.getRpid());
		h5BusiReq.setAccessType(StringUtils.trim(merInfRes.getAccessType())); //接入类型
		h5BusiReq.setAccessName(StringUtils.trim(merInfRes.getAccessName()));//接入名称
		h5BusiReq.setDepBankMerId(StringUtils.trim(merInfRes.getDepBankMerId()));//存管行
		
		Message<ConsumeH5NotifyBusiRes> merBusiRes = consumeBusiServerFeignClient.h5PayNotify(h5BusiReq);
		return merBusiRes;
	}
    private void checkRequestParameter(Map<String, Object> reqMap) {
    	 log.info("验证支付网关签名数据");
    	 Map<String, Object> paraMap = new HashMap<String, Object>(reqMap);
         String sign = StringUtils.trim(reqMap.get(XmlData.SIGN));
         String key = StringUtils.trim(propertyUtil.getProperty("payGate.desSign.key"));
         paraMap.remove(XmlData.SIGN);
         paraMap.remove(XmlData.RETMSG);
         boolean isSign = HashSignHelper.verifySign(sign, paraMap, key); 
         if(!isSign){
         	throw new BusinessException(MerAccessEC.MERSIGN_ERR,"验证网关签名失败");
         }
    }
    
	
	/**
	 * description : 查询商户信息
	 * @author zhangru
	 * @date 2018年5月28日 下午6:44:46
	 * @version 1.0
	**/
	private  MerInfRes getMerInfo(String merId,String rpid){
		// 组织请求memberMgr参数
		Map<String, String> reqMap = new HashMap<String, String>();
		reqMap.put(XmlData.RPID, rpid);
		reqMap.put(XmlData.MERID, merId);

		log.info(String.format("请求平台商户信息,参数为:[%s]", reqMap));
		MerInfRes merInfRes = mgrCommonBusinessImpl.qryMerInfo(reqMap);
		log.info(String.format("平台商户信息查询结果为:[%s]", merInfRes));
		return merInfRes;
	}
}
